require 'erb'

class MicroWiki < Pan::Component

  # RE_LINK_GENERAL = /(\"[A-Za-z0-9 ]+\":[A-Za-z0-9.:\/]+)/
  # RE_LINK_LOCAL = /\"([^\"]+)\":([A-Z][A-Za-z0-9\/]+)/
  RE_LINK_GENERAL = /(<a href=\".+\">.+<\/a>)/
  RE_LINK_LOCAL = /<a href=\"([A-Z][A-Za-z0-9]+)\">([A-Za-z0-9 ]+)<\/a>/
  attr_reader :storage

  def initialize(storage, name="Index", gui=true)
    @storage = storage
    @name = name
    @gui = gui
  end

  def load_page(name)
    @name = name
    @storage.load_page(@name)
  end

  def parts(rc, regex, &block)
    rc.split(regex).map(&block).join("\n")
  end

  def page
    # danger ahead!
    ERB.new(load_page).result
  end
  
  def render_on(html)
    if @gui
      html.div("id"=>"action-links") {
        unless @name == "Index"
          html.link("[home]") { load_page("Index") } 
          html.text(" | ")
        end
        html.link("[edit]") { 
          page = storage.load_page_escaped(@name)
          new_version = call MicroWikiEditor.new(page)
          storage.save_page(@name, new_version)
        }
      }
    end
    rc = RedCloth.new(load_page(@name)).to_html
    rc_linked = register_links(rc, html)
    html.text(rc_linked)
  end

  def register_links(rc, html)
    parts(rc, RE_LINK_GENERAL) do |part|
      if mo = part.match(RE_LINK_LOCAL)
        id = html.register_callback(lambda { load_page(mo[1]) })
        "<a href=\"#{html.build_query(id)}\">#{mo[2]}</a>"
      else
        part
      end
    end
  end
end

class MicroWikiEditor < Pan::Component
  attr_reader :name
  def initialize(page)
    @page = page
  end

  def render_on(html)
    html.heading("PageEditor")

    html.form {
      html.textarea("value"=>@page) # {|val| @page = val}
      html.br
      html.submit("value"=>"Save") { |page|
        answer(page)
      }
    }
  end
end

### Storage alternatives

class PageStorage
  def initialize(dir)
    @dir = dir
  end

  def load_page(name)
    File.exist?(filename(name)) ? File.read(filename(name)) : ""
  end

  def load_page_escaped(name)
    load_page(name).html_safe
  end

  def save_page(name, page)
    File.open(filename(name),"w") { |fh| fh.write(page) }
  end
  
  private
  
  def filename(name)
    "#{@dir}/#{name}"
  end
end

class DBStorage 
  def initialize(klass)
    @klass = klass
  end

  def load_page(name)
    wp = WikiPage.find_by_name(name) 
    wp ? wp.page : ""
  end

  def save_page(name, page)
    wp = WikiPage.find_or_initialize_by_name(name)
    wp.page = page
    wp.save
  end
  
end

